#include <QDateTime>
#include <QFile>

#ifndef Q_OS_WIN

#include "INCLUDE/LEGACYREPLACER.HPP"


void GetSystemTime(PSYSTEMTIME p_st)
{
    const QDateTime currentDateTimeUtc = QDateTime::currentDateTimeUtc();

    p_st->wYear = currentDateTimeUtc.date().year();
    p_st->wMonth= currentDateTimeUtc.date().month();
    p_st->wDayOfWeek= currentDateTimeUtc.date().dayOfWeek();
    p_st->wDay= currentDateTimeUtc.date().day();
    p_st->wHour= currentDateTimeUtc.time().hour();
    p_st->wMinute= currentDateTimeUtc.time().minute();
    p_st->wSecond= currentDateTimeUtc.time().second();
    p_st->wMilliseconds= currentDateTimeUtc.time().msec();
}

BOOL SystemTimeToFileTime(const PSYSTEMTIME p_st, PFILETIME p_ft)
{
    const QDateTime dateTime(
        QDate(p_st->wYear, p_st->wMonth, p_st->wDay),
        QTime(p_st->wHour, p_st->wMinute, p_st->wSecond, p_st->wMilliseconds), Qt::UTC);

    if (!dateTime.isValid())
        return FALSE;

    // Calculate the number of milliseconds since January 1, 1601
    const QDateTime epoch(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
    const qint64 millisecondsSinceEpoch = epoch.msecsTo(dateTime);

    // Convert milliseconds to 100-nanosecond intervals
    const qint64 intervalsSinceEpoch = millisecondsSinceEpoch * 10000;

    // Split the 64-bit value into high and low parts
    p_ft->dwLowDateTime = static_cast<quint32>(intervalsSinceEpoch & 0xFFFFFFFF);
    p_ft->dwHighDateTime = static_cast<quint32>((intervalsSinceEpoch >> 32) & 0xFFFFFFFF);

    return TRUE;
}

BOOL FileTimeToLocalFileTime(const PFILETIME p_ft, PFILETIME p_ftLocalT)
{
    // Combine the low and high parts into a single 64-bit value
    const qint64 intervalsSinceEpoch =
        (static_cast<qint64>(p_ft->dwHighDateTime) << 32) | p_ft->dwLowDateTime;

    // Convert 100-nanosecond intervals to milliseconds
    const qint64 millisecondsSinceEpoch = intervalsSinceEpoch / 10000;

    // Define the epoch start date
    const QDateTime epoch(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);

    // Create a QDateTime object in UTC
    const QDateTime utcDateTime = epoch.addMSecs(millisecondsSinceEpoch);

    // Convert the UTC QDateTime to local time
    const QDateTime localDateTime = utcDateTime.toLocalTime();

    if (!localDateTime.isValid())
        return FALSE;

    // Calculate the milliseconds since epoch for local time
    const qint64 localMillisecondsSinceEpoch = epoch.msecsTo(localDateTime);

    // Convert milliseconds back to 100-nanosecond intervals
    const qint64 localIntervalsSinceEpoch = localMillisecondsSinceEpoch * 10000;

    // Split the 64-bit value into high and low parts
    p_ftLocalT->dwLowDateTime = static_cast<quint32>(localIntervalsSinceEpoch & 0xFFFFFFFF);
    p_ftLocalT->dwHighDateTime = static_cast<quint32>((localIntervalsSinceEpoch >> 32) & 0xFFFFFFFF);

    return TRUE;
}

BOOL FileTimeToSystemTime(const FILETIME *lpFileTime, LPSYSTEMTIME lpSystemTime)
{
    if ((lpFileTime == nullptr) || (lpSystemTime == nullptr))
        return FALSE;

    const QDateTime timeOfTroubles(QDate(1601, 1, 1), QTime(0, 0), Qt::UTC);
    const QDateTime epochOfDarkness(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC);

    ULARGE_INTEGER li;
    li.LowPart = lpFileTime->dwLowDateTime;
    li.HighPart = lpFileTime->dwHighDateTime;

    const qint64 fileTimeInMs = li.QuadPart / 10000; // Convert 100-nanosecond intervals to milliseconds
    const qint64 unixTimeInMs = fileTimeInMs - timeOfTroubles.msecsTo(epochOfDarkness);

    const QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(unixTimeInMs, Qt::UTC);

    if (!dateTime.isValid())
        return FALSE;

    lpSystemTime->wYear = dateTime.date().year();
    lpSystemTime->wMonth = dateTime.date().month();
    lpSystemTime->wDayOfWeek= dateTime.date().dayOfWeek();
    lpSystemTime->wDay = dateTime.date().day();
    lpSystemTime->wHour = dateTime.time().hour();
    lpSystemTime->wMinute = dateTime.time().minute();
    lpSystemTime->wSecond = dateTime.time().second();
    lpSystemTime->wMilliseconds = dateTime.time().msec();

    return TRUE;
}

DWORD timeGetTime()
{
    DWORD result = 0;
    QFile file("/proc/uptime");
    if (file.open(QIODevice::ReadOnly))
        result = file.readLine().split(' ').first().toDouble() * 1000;

    return result;
}

#endif
